package org.dandsoft.blackbox.utils.list;

/**
 * @author Vilyuzhanin Denis (Fin)
 */
public class ListElement<Element> {

    private Element element;
    private ListElement<Element> right;
    private ListElement<Element> left;

    public ListElement(Element element) {
        this.element = element;
    }

    public void connectOver(ListElement element) {
        connectOnLeft(element);
    }

    public void connectUnder(ListElement element) {
        connectOnRight(element);
    }

    public synchronized boolean isDisconnected() {
        return right == null && left == null;
    }

    public synchronized void connectOnRight(ListElement element) {
        if (right != null) {
            ListElement oldRightElement = right;
            element.remove();
            synchronized (oldRightElement) {
                right.left = element;
                element.right = right;
                right = element;
                element.left = this;
            }
        } else {
            element.left = this;
            right = element;
        }
    }

    public synchronized void connectOnLeft(ListElement element) {
        if (left != null) {
            ListElement oldRightElement = right;
            element.remove();
            synchronized (oldRightElement) {
                left.right = element;
                element.left = left;
                left = element;
                element.right = this;
            }
        } else {
            element.right = this;
            left = element;
        }
    }

    public synchronized void remove() {
        final ListElement leftLock = this.left == null ? this : this.left;
        final ListElement rightLock = this.right == null ? this : this.right;
        synchronized (leftLock) {
            synchronized (rightLock) {
                if (left != null) {
                    left.right = right;
                    if (right != null) {
                        right.left = left;
                    }
                }

                if (right != null) {
                    right.left = left;
                    if (left != null) {
                        left.right = right;
                    }
                }
                right = null;
                left = null;
            }
        }
    }

    public Element getElement() {
        return element;
    }

    public ListElement<Element> getBotton() {
        return getRight();
    }

    public ListElement<Element> getTop() {
        return getLeft();
    }

    public ListElement<Element> getRight() {
        return right;
    }

    public ListElement<Element> getLeft() {
        return left;
    }
}
